package br.edu.fucapi.posgraduacao.poo2.sgr.dao.impl;

import java.io.Serializable;
import java.util.List;
import java.util.logging.Logger;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.criteria.CriteriaQuery;
import org.hibernate.Session;
import org.hibernate.Criteria;
import org.hibernate.criterion.Example;
import org.hibernate.criterion.MatchMode;
import org.hibernate.exception.ConstraintViolationException;
import br.edu.fucapi.posgraduacao.poo2.sgr.dao.DAO;



/**
 * @class DaoGenerico.java
 * @author Fabio Oliveira
 * @date 14/01/2013
 * @brief Classe utilizada para persistência dos Dados.
 */

public class DaoGenerico<T,ID extends Serializable> implements DAO<T,ID> {

    private final static String UNIT_NAME = "SGRPU";
    private final static Logger LOGGER = Logger.getLogger("br.edu.fucapi.posgraduacao.poo2.dao.impl");
    
    @PersistenceContext(unitName = UNIT_NAME)
    private transient EntityManager entityManager;

    public void save(T entity){
		try {			
			entityManager.persist(entity);		
		} catch (ConstraintViolationException violation) {
			LOGGER.info(violation.getMessage());
			LOGGER.info(violation.getCause().toString());
			LOGGER.info(violation.getClass().getName());		    
		} catch (IllegalArgumentException argument) {
			LOGGER.info(argument.getMessage());
			LOGGER.info(argument.getCause().toString());
			LOGGER.info(argument.getClass().getName());
		} catch (RuntimeException erro) {
			LOGGER.info(erro.getMessage());
			LOGGER.info(erro.getCause().toString());
			LOGGER.info(erro.getClass().getName());			
		} 	
	}
	
	public void update(T entity){
		try {			
			entityManager.merge(entity);			
		} catch (ConstraintViolationException violation) {
			LOGGER.info(violation.getMessage());
			LOGGER.info(violation.getCause().toString());
			LOGGER.info(violation.getClass().getName());		    
		} catch (IllegalArgumentException argument) {
			LOGGER.info(argument.getMessage());
			LOGGER.info(argument.getCause().toString());
			LOGGER.info(argument.getClass().getName());
		} catch (RuntimeException erro) {
			LOGGER.info(erro.getMessage());
			LOGGER.info(erro.getCause().toString());
			LOGGER.info(erro.getClass().getName());			
		} 	
	}	
	
	public void remove(T entity){
		try {			
			entityManager.remove(entity);			
		} catch (ConstraintViolationException violation) {
			LOGGER.info(violation.getMessage());
			LOGGER.info(violation.getCause().toString());
			LOGGER.info(violation.getClass().getName());		    
		} catch (IllegalArgumentException argument) {
			LOGGER.info(argument.getMessage());
			LOGGER.info(argument.getCause().toString());
			LOGGER.info(argument.getClass().getName());
		} catch (RuntimeException erro) {
			LOGGER.info(erro.getMessage());
			LOGGER.info(erro.getCause().toString());
			LOGGER.info(erro.getClass().getName());			
		} 	
	}
	
	@SuppressWarnings("unchecked")
	public List<T> find(final T entity) throws RuntimeException {
		try {			
			final Session session = (Session) entityManager.getDelegate();
			final Example customerExample = Example.create(entity).excludeZeroes().enableLike(MatchMode.ANYWHERE).ignoreCase();
			final Criteria criteria = session.createCriteria(entity.getClass()).add(customerExample);			
			return criteria.list();
		} catch (ConstraintViolationException violation) {
			LOGGER.info(violation.getMessage());
			LOGGER.info(violation.getCause().toString());
			LOGGER.info(violation.getClass().getName());		    
		} catch (IllegalArgumentException argument) {
			LOGGER.info(argument.getMessage());
			LOGGER.info(argument.getCause().toString());
			LOGGER.info(argument.getClass().getName());
		} catch (RuntimeException erro) {
			LOGGER.info(erro.getMessage());
			LOGGER.info(erro.getCause().toString());
			LOGGER.info(erro.getClass().getName());			
		} 	
		return null;		
	}
	
	@SuppressWarnings("unchecked")
	public List<T> findAll(Class<T> classe){
		try {			
			final CriteriaQuery<T> criteriaQuery = (CriteriaQuery<T>) entityManager.getCriteriaBuilder().createQuery();
			criteriaQuery.select(criteriaQuery.from(classe));
			return entityManager.createQuery(criteriaQuery).getResultList();
		} catch (ConstraintViolationException violation) {
			LOGGER.info(violation.getMessage());
			LOGGER.info(violation.getCause().toString());
			LOGGER.info(violation.getClass().getName());		    
		} catch (IllegalArgumentException argument) {
			LOGGER.info(argument.getMessage());
			LOGGER.info(argument.getCause().toString());
			LOGGER.info(argument.getClass().getName());
		} catch (RuntimeException erro) {
			LOGGER.info(erro.getMessage());
			LOGGER.info(erro.getCause().toString());
			LOGGER.info(erro.getClass().getName());			
		} 	
		return null;
	}
	
	@SuppressWarnings("unchecked")
	public T findById(T entity, Integer id){
		try {			
			T entityAux = (T) entityManager.find(entity.getClass(), id);
			return entityAux;
		} catch (ConstraintViolationException violation) {
			LOGGER.info(violation.getMessage());
			LOGGER.info(violation.getCause().toString());
			LOGGER.info(violation.getClass().getName());		    
		} catch (IllegalArgumentException argument) {
			LOGGER.info(argument.getMessage());
			LOGGER.info(argument.getCause().toString());
			LOGGER.info(argument.getClass().getName());
		} catch (RuntimeException erro) {
			LOGGER.info(erro.getMessage());
			LOGGER.info(erro.getCause().toString());
			LOGGER.info(erro.getClass().getName());			
		} 	
		return null;
	}

	@SuppressWarnings("unchecked")
	public T findByExemplo(final T entity){
		try {
			Session session = (Session) entityManager.getDelegate();
			Example example = Example.create(entity).ignoreCase();			
			Criteria criteria = session.createCriteria(entity.getClass()).add(example);
			return (T) criteria.uniqueResult();
		} catch (IllegalArgumentException argument) {
			LOGGER.info(argument.getMessage());
			LOGGER.info(argument.getCause().toString());
			LOGGER.info(argument.getClass().getName());
			throw argument;
		} catch (RuntimeException erro) {
			LOGGER.info(erro.getMessage());
			LOGGER.info(erro.getCause().toString());
			LOGGER.info(erro.getClass().getName());
			throw erro;
		} 
	}
}
